package cn.poka.device;

import android.os.Handler;

import com.android.hdhe.uhf.reader.SerialPort;
import com.android.hdhe.uhf.reader.Tools;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * RFID设备类
 * @author digl
 */
public class LOCKDevice {

	/** RFID设备实例 */
	private static LOCKDevice rfidDevice;

	/** RFID序列化接口 */
	private static SerialPort rfidSerialPort;

	/** 通过RFID序列化接口，得到命令输入流 */
	private static InputStream mInput;

	/** 通过RFID序列化接口，得到命令输出流 */
	private static OutputStream mOutput;


	private byte[] selectEPC = null;

	public static final byte RESPONSE_OK = 0x00; //响应帧0K

	private static int port = 12;//串口号

	private static int baudRate = 115200;//波特率


	private int COUNTLIMIT = 20;

	private final byte HEAD = (byte) 0xBB;
	private final byte END = (byte) 0x7E;

	private Handler mHandler;

	public LOCKDevice(){

	}

	/**
	 * 获取RFID设备实例，如果实例为空，则进行初始化
	 * @return
	 */
	public static LOCKDevice getInstance(){



		if(rfidDevice == null){
			if(rfidSerialPort == null){
				try {
					rfidSerialPort = new SerialPort(port,
							baudRate, 0);

					rfidSerialPort.psampoweron();

					mInput = rfidSerialPort.getInputStream();
					mOutput = rfidSerialPort.getOutputStream();

					rfidDevice = new LOCKDevice();
				} catch (SecurityException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		}

		return rfidDevice;
	}





	/**
	 * 关闭RFID设备
	 */
	public void close(){
		if(rfidSerialPort != null){
			rfidSerialPort = null;
			try {
				mInput.close();
				mOutput.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if(rfidDevice != null){
			rfidDevice = null;
		}

	}

	/**
	 * 发送指令
	 * @param cmd
	 */
	private void sendCMD(byte[] cmd){
		try {

			mOutput.write(cmd);
			mOutput.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 读取响应帧
	 * @return
	 */
	private byte[] read(){
		byte[] responseData = null;
		byte[] response = null;
		int available = 0 ;
		int index = 0;
		int headIndex = 0;

		try {
			while(index < 10){
				Thread.sleep(50);
				available = mInput.available();

				if(available > 7) break;
				index++;
			}
			if(available > 0){
				responseData = new byte[available];
				mInput.read(responseData);
				for(int i = 0; i < available; i++){
					if(responseData[i] == 0xBB){
						headIndex = i;
						break;
					}
				}
				response = new byte[available - headIndex];
				System.arraycopy(responseData, headIndex, response, 0, response.length);

			}
		} catch (Exception e1) {
			e1.printStackTrace();
		}

		return response;
	}




	public String newRead(){
		List<byte[]> list = inventoryRealTime();
		if(list != null && list.size() > 0){
			byte[] buf = list.get(0);
			String result = Tools.Bytes2HexString(buf, buf.length);
			return result;
		}else{
			return "";
		}
	}

	/**
	 * 实时盘存
	 */
	public List<byte[]> inventoryRealTime() {
		List<byte[]> list = new ArrayList<byte[]>();
		try {

			byte[] cmd = {(byte)0xBB ,(byte)0x00 ,(byte)0x22 ,(byte)0x00 ,
					(byte)0x00 ,(byte)0x22 ,(byte)0x7E};
			sendCMD(cmd);

			byte[] response = this.read();
			if(response != null){
				int responseLength = response.length;


				int start = 0;

				if(responseLength > 15){

					while(responseLength > 5){

						int paraLen = response[start + 4]&0xff;
						int singleCardLen = paraLen + 7;

						if(singleCardLen > responseLength) break;
						byte[] sigleCard = new byte[singleCardLen];
						System.arraycopy(response, start, sigleCard, 0, singleCardLen);

						byte[] resolve = handlerResponse(sigleCard);

						if(resolve != null && paraLen > 5){
							byte[] epcBytes = new byte[paraLen - 5];
							System.arraycopy(resolve, 4, epcBytes, 0, paraLen - 5);

							list.add(epcBytes);
						}
						start+=singleCardLen;
						responseLength-=singleCardLen;
					}
				}else{
					handlerResponse(response);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}



	/**
	 * 处理写标签的响应帧
	 * @param response
	 * @return
	 */
	private byte[] handlerResponse(byte[] response){
		byte[] data = null;
		byte crc = 0x00;
		int responseLength = response.length;
		if(response[0] != HEAD) {

			return data;
		}
		if(response[responseLength - 1] != END){

			return data;
		}
		if(responseLength < 7) return data;

		int lengthHigh = response[3]&0xff;
		int lengthLow = response[4]&0xff;
		int dataLength = lengthHigh*256 + lengthLow;

		crc = checkSum(response);
		if(crc != response[responseLength - 2]){

			return data;
		}
		if(dataLength != 0 && responseLength == dataLength + 7){

			data = new byte[dataLength + 1];
			data[0] = response[2];
			System.arraycopy(response, 5, data, 1, dataLength);
		}
		return data;
	}

	public byte checkSum(byte[] data) {
		byte crc = 0x00;

		for(int i = 1; i < data.length - 2; i++){
			crc+=data[i];
		}
		return crc;
	}

	public byte[] readFrom6C(int memBank, int startAddr, int length, byte[] accessPassword) {

		this.setSelectPara();
		byte cmd[] = {(byte)0xBB ,(byte)0x00 ,(byte)0x39 ,(byte)0x00 ,(
				byte)0x09 ,(byte)0x00 ,(byte)0x00 ,(byte)0xff ,
				(byte)0xff ,(byte)0x03 ,(byte)0x00 ,(byte)0x00 ,(byte)0x00 ,
				(byte)0x02 ,(byte)0x45 ,(byte)0x7E };


		String  dataResult = "";
		String  resultStr = "";
		byte data[] = null;
		if(accessPassword == null || accessPassword.length != 4){
			return null;
		}

		System.arraycopy(accessPassword, 0, cmd, 5, 4);
		cmd[9] = (byte) memBank;
		if(startAddr <= 255){
			cmd[10] = 0x00;
			cmd[11] = (byte)startAddr;
		}else{
			int addrH = startAddr/256;
			int addrL = startAddr%256;
			cmd[10] = (byte)addrH;
			cmd[11] = (byte)addrL;
		}
		if(length <= 255){
			cmd[12] = 0x00;
			cmd[13] = (byte)length;
		}else{
			int lengH = length/256;
			int lengL = length%256;
			cmd[12] = (byte)lengH;
			cmd[13] = (byte)lengL;
		}


		cmd[14] = checkSum(cmd);

		sendCMD(cmd);

		try {
			Thread.sleep(50);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		byte[] response = this.read();
		if(response != null){

			byte[] resolve = handlerResponse(response);

			if(resolve != null){

				if(resolve[0] == (byte)0x39){
					int lengData = resolve.length - resolve[1] - 2;
					data = new byte[lengData];
					System.arraycopy(resolve, resolve[1] + 2, data, 0, lengData);

				}else{

					data = new byte[1];
					data[0] = resolve[1];

				}
			}
		}

		if(data == null){
			return Tools.HexString2Bytes("0");
		}



		return data;
	}

	/**
	 * 写数据
	 * byte[] password 访问密码
	 * int memBank 数据区
	 * int startAddr 起始地址
	 * int wordCnt 写入数据的长度
	 * byte[] data 写入数据
	 * 返回 boolean，true写入数据正确，false写入数据失败
	 */
	public boolean writeTo6C(byte[] password, int memBank, int startAddr,
							 int dataLen, byte[] data) {


		//进行读写操作前线选择操作的卡
		this.setSelectPara();
		if(password == null || password.length != 4){
			return false;
		}
		boolean writeFlag = false;
		int cmdLen = 16 + data.length;
		int parameterLen = 9 + data.length;
		byte[] cmd = new byte[cmdLen];
		cmd[0] = (byte) 0xBB;
		cmd[1] = 0x00;
		cmd[2] = 0x49;
		if(parameterLen < 256){
			cmd[3] = 0x00;
			cmd[4] = (byte)parameterLen;
		}else{
			int paraH = parameterLen/256;
			int paraL = parameterLen%256;
			cmd[3] = (byte)paraH;
			cmd[4] = (byte)paraL;
		}
		System.arraycopy(password, 0, cmd, 5, 4);
		cmd[9] = (byte)memBank;
		if(startAddr < 256){
			cmd[10] = 0x00;
			cmd[11] = (byte) startAddr;
		}else{
			int startH = startAddr/256;
			int startL = startAddr%256;
			cmd[10] = (byte) startH;
			cmd[11] = (byte) startL;
		}
		if(dataLen < 256){
			cmd[12] = 0x00;
			cmd[13] = (byte) dataLen;
		}else{
			int dataLenH = dataLen/256;
			int dataLenL = dataLen%256;
			cmd[12] = (byte)dataLenH;
			cmd[13] = (byte)dataLenL;
		}
		System.arraycopy(data, 0, cmd, 14, data.length);
		cmd[cmdLen -2] = checkSum(cmd);
		cmd[cmdLen - 1] = (byte)0x7E;

		sendCMD(cmd);
		try {
			Thread.sleep(50);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		byte[] response = this.read();
		if(response != null) {

			byte[] resolve = this.handlerResponse(response);
			if(resolve != null){

				if(resolve[0] == 0x49 && resolve[resolve.length - 1] == RESPONSE_OK){
					writeFlag = true;
				}
			}
		}

		return writeFlag;
	}



	/**
	 * 设置select参数指令
	 */
	public void setSelectPara(){
		byte[] cmd = {(byte)0xBB ,(byte)0x00,(byte)0x0C ,(byte)0x00 ,(byte)0x13 ,
				(byte)0x01 ,(byte)0x00 ,(byte)0x00 ,(byte)0x00 ,(byte)0x20 ,(byte)0x60 ,
				(byte)0x00 ,(byte)0x01 ,(byte)0x61 ,(byte)0x05 ,(byte)0xB8 ,(byte)0x03 ,
				(byte)0x48 ,(byte)0x0C ,(byte)0xD0 ,(byte)0x00 ,(byte)0x03 ,(byte)0xD1 ,
				(byte)0x9E ,(byte)0xAD ,(byte)0x7E};
		if(this.selectEPC != null ){

			System.arraycopy(selectEPC, 0, cmd, 12, selectEPC.length);
			cmd[cmd.length - 2] = checkSum(cmd);

			sendCMD(cmd);
			byte[] response = this.read();
			if(response != null){

			}else{
				return;
			}

		}
	}



	/**
	 * 设置select模式
	 * @param epc
	 */

	public void selectEPC(byte[] epc,int md) {
		byte[] cmd = {(byte)0xBB ,(byte)0x00 ,(byte)0x12 ,(byte)0x00,
				(byte)0x01 ,(byte)0x00 ,(byte)0x13 ,(byte)0x7E };
		cmd[5] = (byte)md;
		this.selectEPC = epc;
		sendCMD(cmd);
		byte[] response = this.read();
		if(response != null){

		}else{
			return;
		}

	}



	/**
	 * 设置select参数指令2
	 */
	public void setSelectPara(int sp,byte[] userData){
		byte[] cmd = {(byte)0xBB ,(byte)0x00,(byte)0x0C ,(byte)0x00 ,(byte)0x13 ,
				(byte)0x01 ,(byte)0x00 ,(byte)0x00 ,(byte)0x00 ,(byte)0x20 ,(byte)0x60 ,
				(byte)0x00 ,(byte)0x01 ,(byte)0x61 ,(byte)0x05 ,(byte)0xB8 ,(byte)0x03 ,
				(byte)0x48 ,(byte)0x0C ,(byte)0xD0 ,(byte)0x00 ,(byte)0x03 ,(byte)0xD1 ,
				(byte)0x9E ,(byte)0xAD ,(byte)0x7E};
		if(userData != null ){
			cmd[5] = (byte) sp;

			System.arraycopy(userData, 0, cmd, 12, userData.length);
			cmd[cmd.length - 2] = checkSum(cmd);

			sendCMD(cmd);
			byte[] response = this.read();
			if(response != null){}else{return;};

		}
	}
	/**
	 * 设置select模式2
	 *
	 */

	public void selectEPC(int md) {
		byte[] cmd = {(byte)0xBB ,(byte)0x00 ,(byte)0x12 ,(byte)0x00,
				(byte)0x01 ,(byte)0x01 ,(byte)0x14 ,(byte)0x7E };
		cmd[5] = (byte)md;

		sendCMD(cmd);
		byte[] response = this.read();
		if(response != null){

		}else{
			return;
		}

	}


	/**
	 * 开锁操作
	 */
	public String openLock(String epc){
		String code = "C0";
		byte[] epcRead = Tools.HexString2Bytes(epc);
		selectEPC(epcRead,2);
		String openCode = operate(code);
		selectEPC(1);
		return openCode;
	}


	/**
	 * 闭锁操作
	 */
	public String closeLock(String epc){
		String code = "B0";
		byte[] epcRead = Tools.HexString2Bytes(epc);
		selectEPC(epcRead,2);
		String openCode = operate(code);
		selectEPC(1);
		return openCode;
	}



	/**
	 * 开闭锁操作,将读取的标签与列表中获取的标签相对比再校验开锁
	 */
	private String operate(String operateCode) {

		String readResult = "";

		String message = "000000000000000000" + operateCode + "0000";//24位

		byte[] op = new byte[2];
		op[0] = 0x00;
		if(operateCode.equals("B0")){

			op[1] = (byte) 0xB0;
		}else{
			op[1] = (byte) 0xC0;
		}


		if (message != null && !message.equals("")) {

			byte[] accessPassword = new byte[] { (byte) 0x00, (byte) 0x00,
					(byte) 0x00, (byte) 0x00 };
			if (accessPassword.length != 4) {

				return "密码长度不正确";
			}
			String writeData = message;

			byte[] dataBytes = Tools.HexString2Bytes(writeData);


			LOCKDevice.getInstance().setSelectPara(3,dataBytes);




			boolean writeFlag = LOCKDevice.getInstance().writeTo6C(
					//尝试将起始位改为9数据长度改为1数据改为“B0”或“C0”
					accessPassword, 3, 4, 1, op);

			int count = 0;
			while (!writeFlag) {

				writeFlag = LOCKDevice.getInstance().writeTo6C(accessPassword,
						3, 4, 1, op);
				if (count >= COUNTLIMIT || writeFlag == true) {
					break;
				}
				count++;

			}


			if (writeFlag) {
				if(operateCode.equals("B0")){
					readResult = operateResultRead();
				}else{

					readResult = operateResultRead();
				}
			} else {
				readResult = "写数据失败!";
			}


		}

		return readResult;

	}


	/**
	 * 读取返回数据进行解析，确认返回信息开锁成功、闭锁成功。。。。。。。
	 */

	private String operateResultRead() {
		String operateResult = "";
		String readShow = "";
		try {
			Thread.sleep(2000);

		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		byte[] accessPassword = new byte[] { (byte) 0x00, (byte) 0x00,
				(byte) 0x00, (byte) 0x00 };
		if (accessPassword.length != 4) {

			return "密码长度不正确";
		}

		byte[] resultData = LOCKDevice.getInstance().readFrom6C(3, 0, 19,
				accessPassword);
		operateResult = Tools.Bytes2HexString(resultData, resultData.length);

		int count = 0;
		while (operateResult == null || operateResult.equals("09")) {

			resultData = LOCKDevice.getInstance().readFrom6C(3, 0, 19,
					accessPassword);
			operateResult = Tools.Bytes2HexString(resultData, resultData.length);
			if (count >= COUNTLIMIT || operateResult.length() > 8) {
				break;
			}

			count++;

		}

		if (resultData != null && resultData.length > 0) {
			operateResult = Tools
					.Bytes2HexString(resultData, resultData.length);


			if (operateResult == null) {
				readShow = "操作超时";
			} else if (operateResult.equals("09") || operateResult.length()<50) {
				readShow = "读取结果不成功";
			} else {

				String funCode = operateResult.substring(10, 12);
				String stateCode = operateResult.substring(16, 18);
				if (funCode.equals("C1") || funCode.equals("B1")
						|| funCode.equals("F1")||funCode.equals("00")) {

					if (funCode.equals("C1")) {
						if (stateCode.equals("00")) {

							readShow = "开锁成功";
						}else if(stateCode.equals("50")){

							readShow = "开锁失败，指令序号错误";
						} else if (stateCode.equals("80")) {

							readShow = "开锁失败";
						} else if (stateCode.equals("82")) {

							readShow = "已处于开锁状态";
						} else if (stateCode.equals("84")) {

							readShow = "开锁失败,钞箱异常";
						}
					} else if (funCode.equals("B1")) {
						if (stateCode.equals("00")) {

							readShow = "闭锁成功";
						}else if(stateCode.equals("50")){

							readShow = "闭锁失败，指令序号错误";
						} else if (stateCode.equals("80")) {
							System.out.println("闭锁失败");
							readShow = "闭锁失败";
						} else if (stateCode.equals("82")) {

							readShow = "已处于闭锁状态";
						} else if (stateCode.equals("84")) {

							readShow = "闭锁失败，钞箱异常";
						}
					} else if (funCode.equals("F1")) {
						if (stateCode.equals("00")) {

							readShow = "初始化成功";
						}else if(stateCode.equals("50")){

							readShow = "初始化失败，指令序号错误";
						} else if (stateCode.equals("80")) {

							readShow = "初始化失败";
						} else if (stateCode.equals("82")) {

							readShow = "已初始化成功";
						}
					}else if(funCode.equals("00")) {
						if (stateCode.equals("00")) {

							readShow = "读数据失败或电量低";
						}else if(stateCode.equals("50")){

							readShow = "初始化失败，指令序号错误";
						}
					}

				}
			}
		}

		return readShow;

	}
}




